/*
 * @(#)Database.java 1.0 2000/12/19
 * 
 * Copyright 2000 Thomas Barnekow. All Rights Reserved.
 * 
 * This software is the proprietary information of Thomas Barnekow. Use is
 * subject to license terms.
 */

package tb.provider.jdbc;

import java.sql.*;
import java.util.*;

import tb.provider.*;
import tb.util.*;

/**
 * Database metadata.
 * 
 * @author Thomas Barnekow
 * @version 1.0
 */
public class Database extends AbstractCompoundMetaObject {

	private Connection m_connection = null;

	private boolean m_useCatalog = false;
	private boolean m_useSchema = false;

	private List m_schemas = null;

	public Database(String url, String user, String password)
		throws SQLException {
		this(url, user, password, false, false);
	}

	public Database(String url, String user, String password, boolean useCatalog, boolean useSchema)
		throws SQLException 
	{
		super(url);
		m_connection = DriverManager.getConnection(url, user, password);
		m_useCatalog = useCatalog;
		m_useSchema = useSchema;
	}

	public Database(Connection connection) throws SQLException {
		this(connection, false, false);
	}

	public Database(Connection connection, boolean useCatalog, boolean useSchema)
		throws SQLException 
	{
		super(connection.getMetaData().getURL());
		m_connection = connection;
		m_useCatalog = useCatalog;
		m_useSchema = useSchema;
	}

	/*
	 * AbstractCompoundMetaObject operations
	 */

	protected Collection createElementCollection() throws SQLException {
		Collection schemas = new TreeSet();

		DatabaseMetaData md = getConnection().getMetaData();
		ResultSet result = null;

		if (m_useCatalog && m_useSchema) {
			// TODO:  implement this case
			schemas.add(new Schema("", this));
		} else if (m_useCatalog && md.supportsCatalogsInDataManipulation()) {
			result = md.getCatalogs();
			while (result.next()) {
				schemas.add(new Schema(result.getString(1).toLowerCase(), this));
			}
			result.close();
		} else if (m_useSchema && md.supportsSchemasInTableDefinitions()) {
			result = md.getSchemas();
			while (result.next()) {
				schemas.add(new Schema(result.getString(1).toLowerCase(), this));
			}
			result.close();
		} else {
			schemas.add(new Schema("", this));
		}

		// Done
		return Collections.unmodifiableCollection(schemas);
	}

	/*
	 * This class' operations
	 */

	public final Connection getConnection() {
		return m_connection;
	}

	public MetaObject findEntity(QualifiedName entity) {
		if (entity == null)
			throw new NullPointerException();

		entity = entity.toLowerCase();
		int count = entity.nameComponents();

		// We support a maximum of two name components, like "scott.emp".
		if (count > 2)
			return null;

		// An empty name can only be a "schema" (e.g., MS Access)
		if (count == 0)
			return get("");

		// A qualified name having one component could denote
		// a schema (e.g., Oracle) or a table (e.g., MS Access)
		if (count == 1) {
			MetaObject mo = get(entity.toString());
			if (mo != null) {
				return mo;
			} else {
				// OK, it's not a schema. Let's try a table in the "default"
				// schema.
				return ((CompoundMetaObject) get("")).get(entity.toString());
			}
		}

		// Find entity <schema>.<table>
		CompoundMetaObject schema =
			(CompoundMetaObject) get(entity.getNamespaceName().toString());
		return schema.get(entity.getLastNameComponent());
	}
}